/************************************************************************************\
This source file is part of the Universal Actor Library                              *
For latest info, see http://libuniactor.googlecode.net/                              *
**************************************************************************************
Copyright (c) 2010 Kresimir Spes (kspes@cateia.com)                                  *
*                                                                                    *
* This program is free software; you can redistribute it and/or modify it under      *
* the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php   *
\************************************************************************************/
#include "Actor.h"
#include "Jobs.h"

namespace UniActor
{
	Actor::Actor(hstr name) :
			  mActorName(name),
			  mSpeed(1)
	{
		
	}

	Actor::~Actor()
	{
		clearJobs();
	}

	hstr Actor::getCurrentJobType()
	{
		if (mJobQueue.size() == 0) return "None";
		Job* j=mJobQueue.front();
		return j->getTypeName();
	}
	
	Job* Actor::getCurrentJob()
	{
		if (mJobQueue.size() == 0) return 0;
		return mJobQueue.front();
	}
	
	Job* Actor::getLastJob()
	{
		if (mJobQueue.size() == 0) return 0;
		return mJobQueue.back();
	}
	
	Job* Actor::removeLastJob(bool destroy_job)
	{
		if (mJobQueue.size() == 0) return 0;
		Job* job=mJobQueue.back();
		mJobQueue.pop_back();
		if (destroy_job) { delete job; return 0; }
		else return job;
	}


	void Actor::addJob(Job* job)
	{
		job->setOwner(this);
		mJobQueue.push_back(job);
	}
	
	void Actor::insertJob(unsigned int index,Job* job)
	{
		if (index >= mJobQueue.size()) { addJob(job); return; }
		job->setOwner(this);
		std::list<Job*>::iterator it=mJobQueue.begin();
		for (unsigned int i=0;i<index;i++) it++;
		mJobQueue.insert(it,job);
	}

	void Actor::_popJob()
	{
		if (mJobQueue.size() == 0) return;
		Job* j=mJobQueue.front();
		j->cancel();
		mJobQueue.pop_front();
		delete j;
	}

	void Actor::clearJobs()
	{
		while (mJobQueue.size() > 0) _popJob();
	}
	
	gtypes::Vector3 Actor::getActorPosition()
	{
		return mPosition;
	}

	gtypes::Vector3 Actor::getDirection()
	{
		return mDirection;
	}


	void Actor::setPosition(float x,float y,float z)
	{
		gtypes::Vector3 old=mPosition;
		mPosition.set(x,y,z);
		OnPositionChanged(old);
	}
	
	void Actor::setPosition(gtypes::Vector3 v)
	{
		setPosition(v.x,v.y,v.z);
	}

	void Actor::setDirection(float x,float y,float z)
	{
		gtypes::Vector3 old=mDirection;
		mDirection.set(x,y,z);
		OnDirectionChanged(old);
	}
	
	void Actor::setDirection(gtypes::Vector3 v)
	{
		setDirection(v.x,v.y,v.z);
	}

	void Actor::update(float time_increase)
	{
		Job* j;
		while (mJobQueue.size())
		{
			j=mJobQueue.front();
			if (!j->isExecuting()) j->start();
			if (j != mJobQueue.front()) continue; // sometimes, jobs can call actions that kill the current job queue. beware!
			if (j->isDone())
			{
				time_increase+=j->calcOvertime();
				_popJob();
				continue;
			}
			else
				j->update(time_increase);
			break;
		}
	}

	int Actor::getJobQueueSize()
	{
		return (int)mJobQueue.size();
	}

	void Actor::OnStartMovement() {}
	void Actor::OnEndMovement() {}
	void Actor::OnDirectionChanged(gtypes::Vector3 old) {}
	void Actor::OnPositionChanged(gtypes::Vector3 old) {}
	void Actor::OnStartAnimation(chstr ani_name) {}
	void Actor::OnEndAnimation(chstr ani_name) {}
	void Actor::setAnimationFrame(chstr ani_name, float time) {}
	float Actor::getAnimationTime(chstr ani_name) { return 1; }

}
